package cn.xiaolang.thread.concurrent;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 并发共享资源
 *
 * @author fuhw/Dean
 * @date 2020-03-06
 */
@Slf4j
public class ShareResource {

    // 存放资源的容器
    private List<String> resContainer = Lists.newArrayList();
    private Random random = new Random();
    private static final String PUT_STRING = "向容器添加商品[{}]";
    private static final String GAIN_STRING = "从容器取出商品[{}]";

    public void put(String name) {
        log.info(PUT_STRING, name);
        resContainer.add(name);
    }

    public void gain() {
        if (!resContainer.isEmpty()) {
            int index = random.nextInt(resContainer.size());
//            log.info(GAIN_STRING, resContainer.get(index));
            resContainer.remove(index);
        } else {
            log.info("未取出商品");
        }
    }

    //对象锁
    private final Object lockObj = new Object();

    public void putSyncIfWaitNotify(String name) {
        synchronized (lockObj) {
            if (resContainer.size() > 10) {
                try {
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info(PUT_STRING, name);
            resContainer.add(name);
            //唤醒处于等待的线程
            lockObj.notify();
        }
    }

    public void gainSyncIfWaitNotify() {
        synchronized (lockObj) {
            //容器空了，等待生产着生产商品
            if (resContainer.isEmpty()) {
                try {
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (!resContainer.isEmpty()) {
                int index = random.nextInt(resContainer.size());
                if (index != resContainer.size()) {
//                    log.info(GAIN_STRING, resContainer.get(index));
                    resContainer.remove(index);
                }
            }
            //唤醒处于等待的线程
            lockObj.notify();
        }
    }

    public void putSyncWhileWaitNotifyAll(String name) {
        synchronized (lockObj) {
            while (resContainer.size() > 10) {
                try {
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info(PUT_STRING, name);
            resContainer.add(name);
            lockObj.notifyAll();
        }
    }

    public void gainSyncWhileWaitNotifyAll() {
        synchronized (lockObj) {
            while (resContainer.isEmpty()) {
                try {
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            int index = random.nextInt(resContainer.size());
//            log.info(GAIN_STRING, resContainer.get(index));
            resContainer.remove(index);
            lockObj.notifyAll();
        }
    }

    //@since JDK 1.5 的锁机制
    private Lock lock = new ReentrantLock();
    private Condition conProduce = lock.newCondition();
    private Condition conConsumer = lock.newCondition();


    public void putLockCondition(String name) {
        lock.lock();
        try {
            while (resContainer.size() > 10) {
                try {
                    // 容器满了，生产者等待
                    conProduce.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info(PUT_STRING, name);
            resContainer.add(name);
            // 唤醒消费消费
            conConsumer.signal();
        } finally {
            lock.unlock();
        }
    }

    public void gainLockCondition() {
        lock.lock();
        try {
            while (resContainer.isEmpty()) {
                try {
                    // 容器中没有商品了，消费线程等待，等待生产着生产商品 ;注意：使用的await,signal
                    conConsumer.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            int index = random.nextInt(resContainer.size());
            log.info(GAIN_STRING, resContainer.get(index));
            resContainer.remove(index);
            //唤醒生成者生产商品
            conProduce.signal();
        } finally {
            lock.unlock();
        }
    }
}
